﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework;
using XGE.ComponentSystem;
using System.Threading;

namespace XGE.Physics
{
    public class PhysicsSystem
    {
        
        private Rectangle screenBounds;
        private float BoundsDampener = 0.8f;
        private float Gravity = 0.0f;
        ICoreGame game;
        public PhysicsSystem(Core Game)
        {
            game = Game;
            screenBounds = new Rectangle(0, 0, Game.graphics.PreferredBackBufferWidth, Game.graphics.PreferredBackBufferHeight);
        }
        //This Should implement Multi threading and Asynchronus Delegates  to run more effeciently with thousands of objects
        public void UpdatePhysics(ref ComponentCollection Components, GameTime gameTime)
        {
            CalcGravity(gameTime);
            List<PhysicsInfo> PhysicsObjects = GetPhysicsInfoList(ref Components);
            for (int i = 0; i < Components.Count; i++)
            {
                if (Components[i] is iPhysicsObject)
                {
                    ((iPhysicsObject)Components[i]).physicsInformation = UpdateObject(((iPhysicsObject)Components[i]).physicsInformation);
                }
            }
            GC.Collect();
        }

        public List<PhysicsInfo> GetPhysicsInfoList(ref ComponentCollection components)
        {
            List<PhysicsInfo> physicsInfo = new List<PhysicsInfo>();
            
            foreach(iPhysicsObject PhysicsObject in components)
            {
                physicsInfo.Add(PhysicsObject.physicsInformation);
            }
            return physicsInfo;
        }

        private PhysicsInfo UpdateObject(PhysicsInfo physicsInformation)
        {
            UpdateGravity(ref physicsInformation);
            UpdatePosition(ref physicsInformation);
            CheckWallCollision(ref physicsInformation);
            return physicsInformation;
        }
        //Method will be implemented next build
        private void CheckCollisionBetweenObjects(ref PhysicsInfo physicsInformation, ref List<PhysicsInfo> physicObjects)
        {
            foreach (PhysicsInfo collidableObject in physicObjects.Except<PhysicsInfo>(physicsInformation))
            {
 
            }
        }

        private void CheckWallCollision(ref PhysicsInfo physicsInformation)
        {
            if (physicsInformation.collisionBox.Left < 0)
            {
                physicsInformation.Velocity.X = -(physicsInformation.Velocity.X);
                physicsInformation.position.X = 0;
                physicsInformation.UpdateCollisionBox();
            }
            if (physicsInformation.collisionBox.Right > 800)
            {
                physicsInformation.Velocity.X = -(physicsInformation.Velocity.X);
                physicsInformation.position.X = 800 - physicsInformation.collisionBox.Width;
                physicsInformation.UpdateCollisionBox();
            }
            if (physicsInformation.collisionBox.Bottom > 600)
            {
                physicsInformation.Velocity.Y = -(physicsInformation.Velocity.Y) * physicsInformation.Resitance;
                if (-physicsInformation.Velocity.Y < 0.4)
                    physicsInformation.Velocity.Y = 0.0f;
                physicsInformation.position.Y = 600 - physicsInformation.collisionBox.Height;
                physicsInformation.UpdateCollisionBox();
                game.BreakTest = true;
                return;
            }
            game.BreakTest = false;
        }

        private void CalcGravity(GameTime gameTime)
        {
            Gravity = (float)(9.8 * gameTime.ElapsedGameTime.Milliseconds/10000);
        }
        private void UpdateGravity(ref PhysicsInfo physicsInformation)
        {
            physicsInformation.Velocity.Y += Gravity;
        }
        private void UpdatePosition(ref PhysicsInfo physicsInformation)
        {
            physicsInformation.position += physicsInformation.Velocity;
            physicsInformation.UpdateCollisionBox();
        }
        
    }
}
